#include <linux/pci.h>
#include <linux/irq.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/dmi.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/otg.h>
#include <linux/usb/dwc_otg3.h>
#include <linux/types.h>
#include "xhci_ts.h"

static struct xhci_hcd *xhci;
static const char hcd_name[] = "xhci_ts";

static const struct hc_driver xhci_pltf_hc_driver = {
	.description =		hcd_name,
	.product_desc =		"xHCI Host Controller",
	.hcd_priv_size =	sizeof(struct xhci_hcd *),
//	.irq =			xhci_irq,
	.flags =		HCD_MEMORY | HCD_USB3 | HCD_SHARED,
};

static int xhci_dwc_drv_probe(struct platform_device *pdev)
{
	struct usb_phy *usb_phy = usb_get_transceiver();
	struct usb_hcd *hcd;
	struct dwc_device_par *pdata;
	struct resource *res;
	printk("zoucao %s\n", __func__);

	xhci = kzalloc(sizeof(struct xhci_hcd) ,GFP_KERNEL);
	pdata = (struct dwc_device_par *)pdev->dev.platform_data;
	if (!pdata) {
		dev_err(&pdev->dev,
			"No platform data for %s.\n", dev_name(&pdev->dev));
		return -ENODEV;
	}


	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!res) {
		printk("zoucao %s palt rest err\n", __func__);
		return 1;
	}

	xhci->otg_irqnum = res->start;
	return 0;
	//xhci->hcd = usb_create_hcd(&xhci_pltf_hc_driver, &pdev->dev,
	//			dev_name(&pdev->dev));

	hcd->regs = pdata->io_addr;
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev,
			"Found HC with no IRQ. Check %s setup!\n",
			dev_name(&pdev->dev));
		return -ENODEV;
	}
	hcd->rsrc_start = res->start;
	hcd->rsrc_len = res->end - res->start;

	if (usb_phy) {
		otg_set_host(usb_phy->otg, &hcd->self);
		usb_put_transceiver(usb_phy);
	}
	hcd->rpm_control = 1;
	hcd->rpm_resume = 0;
	hcd->rpm_early_resume = 0;
	platform_set_drvdata(pdev, hcd);
	return 0;
}

static int xhci_dwc_drv_remove(struct platform_device *pdev)
{
	usb_remove_hcd(xhci->hcd);
	usb_put_hcd(xhci->hcd);
	kfree(xhci);
	printk("zoucao %s\n", __func__);
	return 0;
}
#define XHCI_PLATFORM_DRIVER (xhci_dwc_driver)
static struct platform_driver xhci_dwc_driver = {
	.probe = xhci_dwc_drv_probe,
	.remove = xhci_dwc_drv_remove,
	.driver = {
		.name = "dwc3-host",
#ifdef CONFIG_PM
//		.pm = &dwc_usb_hcd_pm_ops
#endif
	},
};

int xhci_hcd_init(void)
{
	return	platform_driver_register(&XHCI_PLATFORM_DRIVER);
}

void xhci_hcd_cleanup(void)
{
	platform_driver_unregister(&XHCI_PLATFORM_DRIVER);
}
